#! /usr/bin/env python3

import glob
import sys

sys.path.insert(0, glob.glob('../../')[0])

from match_server.match_service import Match
from django.core.cache import cache

from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer

from queue import Queue
from time import sleep
from threading import Thread

from acapp.asgi import channel_layer
from asgiref.sync import async_to_sync  # 多线程变单线程

queue = Queue()  # 消息队列

multi_cnt = 2

class Pool:
    def __init__(self):
        self.players = []

    def add_player(self, player):
        self.players.append(player)

    # 检验是否匹配
    def check_match(self, a, b):
        # if a.username == b.username:
        #     return False
        dt = abs(a.score - b.score)
        a_max_dif = a.waiting_time * 50
        b_max_dif = b.waiting_time * 50
        return dt <= a_max_dif and dt <= b_max_dif

    def match_success(self, ps):
        message = "Match success:"
        room_name = "room"
        for p in ps:
            message += ' ' + p.username
            room_name += '-' + p.uuid
        print(message)
        # print("Match success: %s %s %s" % (ps[0].username, ps[1].username, ps[2].username))
        # room_name = f"room-{ps[0].uuid}-{ps[1].uuid}-{ps[2].uuid}"
        players = []
        for p in ps:
            # 将玩家加入用户组
            async_to_sync(channel_layer.group_add)(room_name, p.channel_name)
            players.append({
                "uuid": p.uuid,
                "username": p.username,
                "photo": p.photo,
                "hp": 100,
            })
        # 加入redis
        cache.set(room_name, players, 3600)
        for p in ps:
            # 匹配服务调用ws服务
            async_to_sync(channel_layer.group_send)(
                room_name,
                {
                    "type": "group_send_event",
                    "event": "create_player",
                    "uuid": p.uuid,
                    "username": p.username,
                    "photo": p.photo,
                }
            )

    def increase_waiting_time(self):
        for p in self.players:
            p.waiting_time += 1

    # 匹配
    def match(self):
        while len(self.players) >= multi_cnt:
            self.players = sorted(self.players, key=lambda p: p.score)
            flag = False
            for i in range(len(self.players) - (multi_cnt - 1)):
                # 修改多人匹配数量
                players_list = []
                for j in range(i, i + multi_cnt):
                    players_list.append(self.players[j])
                n = len(players_list)
                is_success_match = True
                for x in range(n):
                    for y in range(n):
                        if x <= y:
                            continue
                        if not self.check_match(players_list[x], players_list[y]):
                            is_success_match = False
                            break
                    if not is_success_match:
                        break
                if is_success_match:
                    self.match_success(players_list)
                    self.players = self.players[: i] + self.players[i + multi_cnt: ]
                    flag = True
                    break

                # a, b, c = self.players[i], self.players[i + 1], self.players[i + 2]
                # if self.check_match(a, b) and self.check_match(a, c) and self.check_match(b, c):
                #     self.match_success([a, b, c])
                #     self.players = self.players[:i] + self.players[i + 3:]
                #     flag = True
                #     break

            if not flag:
                break
        self.increase_waiting_time()


class Player:
    def __init__(self, score, uuid, username, photo, channel_name):
        self.score = score
        self.uuid = uuid
        self.username = username
        self.photo = photo
        self.channel_name = channel_name
        self.waiting_time = 0  # 等待时间


class MatchHandler:
    def add_player(self, score, uuid, username, photo, channel_name):
        print(f"Add player: {username} {score}")
        player = Player(score, uuid, username, photo, channel_name)
        queue.put(player)
        return 0


# 生产者-消费者模型 此函数用来消耗消息队列中的元素
def worker():
    pool = Pool()
    while True:
        player = get_player_from_queue()
        if player:
            pool.add_player(player)
        else:
            pool.match()
            sleep(1)


# 队列中是否有元素
def get_player_from_queue():
    try:
        return queue.get_nowait()
    except:
        return None


if __name__ == '__main__':
    handler = MatchHandler()
    processor = Match.Processor(handler)
    transport = TSocket.TServerSocket(host='127.0.0.1', port=9090)
    tfactory = TTransport.TBufferedTransportFactory()
    pfactory = TBinaryProtocol.TBinaryProtocolFactory()

    # 单线程
    # server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)

    # You could do one of these for a multithreaded server
    # 多线程
    server = TServer.TThreadedServer(
        processor, transport, tfactory, pfactory)
    # 限制线程个数
    # server = TServer.TThreadPoolServer(
    #     processor, transport, tfactory, pfactory)

    Thread(target=worker, daemon=True).start()  # deamon为True表示杀掉主线程此进程被关闭 否则不被关闭

    print('Starting the server...')
    server.serve()
    print('done.')
